// test.go
package main

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"encoding/json"
	"io"
	"mime/multipart"
	"os"
	"runtime"
	"strconv"
	"strings"

	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"restsrv"
	"time"
)

func PostJson(url string, body []byte) ([]byte, error) {

	if strings.HasPrefix(url, "https") {
		return sendWithSec("POST", url, body)
	} else {
		return send("POST", url, body)
	}

}

func GetApp() ([]byte, error) {

	return sendWithSec("GET", globalConf.callRest+"/test/app", []byte(""))

}

func sendWithSec(method string, url string, body []byte) ([]byte, error) {

	reqBody := bytes.NewBuffer(body)

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			Dial: func(netw, addr string) (net.Conn, error) {
				conn, err := net.DialTimeout(netw, addr, time.Second*1)
				if err != nil {
					return nil, err
				}
				conn.SetDeadline(time.Now().Add(time.Second * 1))
				return conn, nil
			},
			ResponseHeaderTimeout: time.Second * 1,
		},
	}

	req, err := http.NewRequest(method, url, reqBody)
	if nil != err {
		fmt.Print("new request failed.", err)
		return nil, err
	}

	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json;charset=utf-8")
	req.Header.Set("Connection", "close")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Print("http client failed:", err)
		return nil, errors.New("http request failed!")
	}

	defer resp.Body.Close()

	if 200 != resp.StatusCode {
		fmt.Print("post url ", url, "failed.status code:", resp.StatusCode)
		return nil, errors.New("return status code not 200")
	}

	resbody, err := ioutil.ReadAll(resp.Body)
	return resbody, err
}

func send(method string, url string, body []byte) ([]byte, error) {

	reqBody := bytes.NewBuffer(body)

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			Dial: func(netw, addr string) (net.Conn, error) {
				conn, err := net.DialTimeout(netw, addr, time.Second*1)
				if err != nil {
					return nil, err
				}
				conn.SetDeadline(time.Now().Add(time.Second * 1))
				return conn, nil
			},
			ResponseHeaderTimeout: time.Second * 1,
		},
	}

	req, err := http.NewRequest(method, url, reqBody)
	if nil != err {
		fmt.Print("new request failed.", err)
		return nil, err
	}

	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json;charset=utf-8")
	req.Header.Set("Connection", "close")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Print("http client failed:", err)
		return nil, errors.New("http request failed!")
	}

	defer resp.Body.Close()

	if 200 != resp.StatusCode {
		fmt.Print("post url ", url, "failed.status code:", resp.StatusCode)
		return nil, errors.New("return status code not 200")
	}

	resbody, err := ioutil.ReadAll(resp.Body)
	return resbody, err
}

type outCallInfo struct {
	AppId   string `json:"appid"`
	Caller  string `json:"caller"`
	Called  string `json:"called"`
	Data    string `json:"data"`
	Timeout int    `json:"timeout"`
}

type playInfo struct {
	Appid     string `json:"appId"`
	CallId    string `json:"callId"`
	GetKey    int    `json:"getkey"`
	Flag      int    `json:"playFlag"`
	Voice     string `json:"voiceStr"`
	PlayTime  int    `json:"playTime"`
	MaxKey    int    `json:"maxRevCnt"`
	Key2End   string `json:"key2End"`
	SpaceTime int    `json:"spaceTime"`
	TotalTime int    `json:"totalTime"`
	Data      string `json:"data"`
}

type rspon struct {
	Code   string `json:"retCode"`
	Appid  string `json:"appid"`
	Callid string `json:"callid"`
}

type confInfo struct {
	sid        string
	token      string
	appId      string
	callId     string
	httpServ   string
	callRest   string
	customRest string
	partnerId  string
	partnerKey string
	number     string
	number2    string
	fee        float64
	callfee    float64
	dbtype     string
	dbname     string
	dbuser     string
	dbpwd      string
	dbaddr     string
	recordPath string
	debug      bool
	redis      string
	testNum    string
	caller2    string
	display    string
	timeOut    int
	ai         bool
	callDelay  int
	callTask   int
}

var globalConf confInfo

func (g *confInfo) SetCallId(callId string) {
	g.callId = callId
}

func (g *confInfo) GetCallId() string {
	return g.callId
}

func GetDebug() bool {
	return globalConf.debug
}

func GetRecordPath() string {
	return globalConf.recordPath
}

func GetNumber() string {
	return globalConf.number
}

func GetAppid() string {
	return globalConf.appId
}

func GetCallRestUrl() string {
	return globalConf.callRest
}

func GetHttpServ() string {
	return globalConf.httpServ
}

func GetSid() string {
	return globalConf.sid
}

func GetToken() string {
	return globalConf.token
}

func GetPartnerKey() string {
	return globalConf.partnerKey
}

func GetPartnerId() string {
	return globalConf.partnerId
}

func GetCustomRest() string {
	return globalConf.customRest
}

func GetFee() float64 {
	return globalConf.fee
}

func GetCallFee() float64 {
	return globalConf.callfee
}

func GetDbUser() string {
	return globalConf.dbuser
}

func GetDbUserPwd() string {
	return globalConf.dbpwd
}

func GetDbServer() string {
	return globalConf.dbaddr
}

func GetDbName() string {
	return globalConf.dbname
}

func GetDbType() string {
	return globalConf.dbtype
}

func GetRedisAddr() string {
	return globalConf.redis
}

func parseConf(conf string) {

	if 0 == strings.Index(conf, "#") || len(conf) == 0 {
		return
	}

	info := strings.Split(conf, "=")

	if len(info[1]) > 0 {

		if info[0] == "token" {
			fmt.Println("set :", info[0], info[1])
			globalConf.token = info[1]
		} else if info[0] == "sid" {
			fmt.Println("set :", info[0], info[1])
			globalConf.sid = info[1]
		} else if info[0] == "appid" {
			fmt.Println("set :", info[0], info[1])
			globalConf.appId = info[1]
		} else if info[0] == "callRest" {
			globalConf.callRest = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "server" {
			globalConf.httpServ = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "customRest" {
			globalConf.customRest = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "partner_id" {
			globalConf.partnerId = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "partner_key" {
			globalConf.partnerKey = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "number" {
			globalConf.number = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "dbtype" {
			globalConf.dbtype = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "dbname" {
			globalConf.dbname = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "dbuser" {
			globalConf.dbuser = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "dbpwd" {
			globalConf.dbpwd = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "dbaddr" {
			globalConf.dbaddr = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "recordpath" {
			globalConf.recordPath = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "debug" {
			globalConf.debug = strings.HasPrefix("true", info[1])
			fmt.Println("set :", info[0], strings.HasPrefix("true", info[1]))
		} else if info[0] == "redis" {
			globalConf.redis = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "caller" {
			globalConf.testNum = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "caller2" {
			globalConf.caller2 = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "number2" {
			globalConf.number2 = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "display" {
			globalConf.display = info[1]
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "time" {
			globalConf.timeOut, _ = strconv.Atoi(info[1])
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "ai" {
			if info[1] == "true" {
				globalConf.ai = true
			} else {
				globalConf.ai = false
			}
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "callDelay" {
			globalConf.callDelay, _ = strconv.Atoi(info[1])
			fmt.Println("set :", info[0], info[1])
		} else if info[0] == "callTask" {
			globalConf.callTask, _ = strconv.Atoi(info[1])
			fmt.Println("set :", info[0], info[1])
		}

	}
}

func LoadGlobalConf(fileName string) {

	f, err := os.Open(fileName)
	if err != nil {
		fmt.Fprintf(os.Stderr, ("配置文件(%s)不存在:%s"), fileName, err.Error())
		os.Exit(1)
	}

	buf := bufio.NewReader(f)
	for {
		line, err := buf.ReadString('\n')
		line = strings.TrimSpace(line)
		parseConf(line)
		if err != nil {
			if err == io.EOF {
				break
			}
			break
		}
	}

	if len(globalConf.number) == 0 {
		fmt.Fprintf(os.Stderr, "test number is not set\n")
		os.Exit(1)
	}

}

func testCall(callMax int) {

	for i := 0; i < callMax; i++ {
		tel := fmt.Sprintf("1%.6d", i)

		restsrv.TestOutCall(globalConf.appId, tel, globalConf.testNum)
		time.Sleep(10 * time.Millisecond)
	}

}

func readFile(file string, numberChan chan string) {

	f, err := os.Open(file)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	rd := bufio.NewReader(f)

	for i := 0; ; i++ {
		line, _, err := rd.ReadLine() //以'\n'为结束符读入一行
		if err != nil || io.EOF == err {
			break
		}

		numberChan <- string(line)
	}
}

func testCallAlways(number int, caller string) {

	baseNumber := 10000
	calls := 0

	go func() {
		for {

			if globalConf.callTask > 0 && calls >= number {
				fmt.Printf("call out number:%v finished.", calls)
				break
			}

			calls++
			tel := fmt.Sprintf("%d", baseNumber)
			baseNumber++

			fmt.Printf("\nstart call : %s ,ai enable:%v \n", tel, globalConf.ai)
			if globalConf.ai {
				restsrv.TestOutCallWithAi(globalConf.appId, tel, caller)
			} else {
				restsrv.TestOutCall(globalConf.appId, tel, caller)
			}

			//restsrv.TestCallNotify(globalConf.appId, tel, globalConf.testNum, "")
			time.Sleep(time.Duration(globalConf.callDelay) * time.Millisecond)
		}

		//结束后，打开回调打印
		time.Sleep(10 * time.Second)
		globalConf.debug = true
		restsrv.DebugOn()
	}()

}

func testUploadFile(appid string) error {

	filePath := []string{"/Users/Peter/Downloads/voice/putvoice.sh", "/Users/Peter/Downloads/voice/voiceup.sh"}
	url := "http://127.0.0.1/ipcc/manager/file"

	body := new(bytes.Buffer)
	w := multipart.NewWriter(body)

	//form
	w.WriteField("appId", appid)

	//file
	for i := 0; i < len(filePath); i++ {

		name := fmt.Sprintf("test%d", i)
		file, err := w.CreateFormFile("file", name)

		if err != nil {
			fmt.Errorf("create form file failed %s:", err.Error())
			return err
		}

		file_data, err := ioutil.ReadFile(filePath[i])
		if err != nil {
			fmt.Errorf("readfile error %s", err.Error())
			return err
		}

		file.Write(file_data)

		fmt.Printf("file add :%s ,%s\n", name, filePath[i])
	}
	w.Close()

	//request
	req, _ := http.NewRequest("POST", url, body)
	req.Header.Set("Content-Type", w.FormDataContentType())

	req.Header.Write(os.Stdout)

	fmt.Println(req)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Errorf("upload file %s  to %s error", filePath, err.Error())
		return err
	}

	defer resp.Body.Close()

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Errorf("readAll err %s", err.Error())
		return err
	}

	fmt.Print("result:", resp.StatusCode, " respone:", string(data), "\n")

	time.Sleep(10 * time.Second)
	return nil

}

var testVoice string

func testTimeParse() {

	str := "8088-20180202164125414147441-37055e3d3f3055d3-out"
	p := strings.Index(str, "-")

	fmt.Printf("parse :%s\n", str[p+1:p+15])

	t, err := time.ParseInLocation("20060102150405", "20180304144657", time.Local)
	fmt.Println("pares time result:", err, t.Format("2006-01-02 15:04:05"))
}

func main() {

	LoadGlobalConf("./test.conf")

	restsrv.TestHost = globalConf.callRest

	res, _ := GetApp()
	fmt.Println("get app:", string(res))
	restsrv.Init()

	go restsrv.CreateGate(globalConf.httpServ)
	/*
		if false {

			if strings.HasPrefix(os.Args[1], "callbackSip") {
				restsrv.CallType = "callback"
				restsrv.CustermorNumer = globalConf.number
				restsrv.TestOutCallBackSip(globalConf.appId, globalConf.number, globalConf.number2, globalConf.testNum, globalConf.caller2)
			} else if strings.HasPrefix(os.Args[1], "callback") {
				restsrv.CallType = "callback"
				restsrv.CustermorNumer = globalConf.number2
				restsrv.TestOutCallBack(globalConf.appId, globalConf.number, globalConf.number2, globalConf.display, globalConf.testNum)
			} else if strings.HasPrefix(os.Args[1], "WEBANK") {
				restsrv.TestVoice = os.Args[1]
				restsrv.TestOutCall(globalConf.appId, globalConf.number, globalConf.testNum)
			} else if strings.HasPrefix(os.Args[1], "notify") {

				restsrv.TestCallNotify(globalConf.appId, globalConf.number, globalConf.testNum, "")

			} else if strings.HasPrefix(os.Args[1], "transfer") {
				restsrv.TestCallNotifyTransfer(globalConf.appId, globalConf.number, globalConf.testNum, globalConf.number2, globalConf.timeOut)
			} else if strings.HasPrefix(os.Args[1], "asr") {
				restsrv.TestOutCallWithAi(globalConf.appId, globalConf.number, globalConf.testNum)
			} else if strings.HasPrefix(os.Args[1], "always") {

			} else {

				number, err := strconv.Atoi(os.Args[1])
				if err != nil {
					fmt.Println("convert failed err:", err)
					number = 100
				}

				testCall(number)
			}

		}
	*/
	console_main()
}

func sendstatus() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	ss1 := `{"event":"callstatrpt","callId":"`
	ss2 := `","appId":"247e35ff320a4142a105024055c367ce","serviceId":"13045098689","dir":1,"ansCode":2,"timeStamp":"20180519180252052"}`

	//ss1 := `{"event":"calldisconnectrpt","callId":"`
	//ss2 := `","appId":"247e35ff320a4142a1050240eeeeeeee","dir":1,"fileName":"","reason":0,"timeStamp":"20180521201232108"}`

	webank := `https://txc-capapi.test.webank.com/cb/s/ivr/callback`

	type status struct {
		CallId string `json:"callId"`
	}

	f, err := os.Open("err.log")
	if err != nil {
		fmt.Fprintf(os.Stderr, ("配置文件(%s)不存在:%s"), "err.log", err.Error())
		os.Exit(1)
	}
	i := 0
	buf := bufio.NewReader(f)
	for {
		i++
		line, err := buf.ReadString('\n')
		line = strings.TrimSpace(line)

		var s status

		err = json.Unmarshal([]byte(line), &s)
		if nil == err {
			fmt.Printf("send callid:%s\n", s.CallId)

			ss := ss1 + s.CallId + ss2

			go func() {
				fmt.Printf("%4d ready to send:%s,to %s\n", i, ss, webank)
				res, err := restsrv.PostJson(webank, []byte(ss))
				fmt.Println(string(res), err)
			}()
		}

		if err != nil {
			if err == io.EOF {
				break
			}
			break
		}
	}

	for {
		time.Sleep(10 * time.Second)
	}
}

func tcptest() {

	tcpAddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:7677")
	if err != nil {
		fmt.Print("ResolveTCPAddr wrong:", err)
		return
	}

	conn, err := net.DialTCP("tcp", nil, tcpAddr)

	if err != nil {
		fmt.Print("dial wrong:", err)
		return
	}

	for {
		n, err := conn.Write([]byte("hello word"))
		fmt.Print("write : ", n, err)

		result, err := ioutil.ReadAll(conn)
		fmt.Print("read : ", string(result), err)

		time.Sleep(10 * time.Second)
	}
}
